package com.leoman.service.impl;

import com.leoman.controller.common.CommonController;
import com.leoman.core.Constant;
import com.leoman.dao.AttentionDao;
import com.leoman.entity.Attention;
import com.leoman.entity.User;
import com.leoman.entity.vo.UserInfoVo;
import com.leoman.exception.AttentionExistException;
import com.leoman.exception.AttentionNotFindException;
import com.leoman.exception.ParamErrorException;
import com.leoman.service.AttentionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * AttentionServiceImpl
 * Created by 涂奕恒 on 2016/11/23 0023 下午 3:56.
 */
@Service
public class AttentionServiceImpl implements AttentionService {

    @Autowired
    private AttentionDao attentionDao;

    @Override
    public List<Attention> findAll() {
        return attentionDao.findAll();
    }

    @Override
    public Page<Attention> find(int pageNum, int pageSize) {
        return attentionDao.findAll(new PageRequest(pageNum - 1, pageSize, Sort.Direction.DESC, "id"));
    }

    @Override
    public Page<Attention> find(int pageNum) {
        return find(pageNum, Constant.PAGE_DEF_SIZE);
    }

    @Override
    public Attention getById(int id) {
        return attentionDao.findOne(id);
    }

    @Override
    public void deleteById(int id) {
        attentionDao.delete(id);
    }

    @Override
    public Attention create(Attention attention) {
        return attentionDao.save(attention);
    }

    @Override
    public Attention update(Attention attention) {
        return attentionDao.save(attention);
    }

    @Override
    @Transactional
    public void deleteAll(int[] ids) {
        for (int id : ids) {
            deleteById(id);
        }
    }

    @Override
    public List<UserInfoVo> findThreeUserInfo(Integer userId) {
        List<UserInfoVo> list = new ArrayList<>();
        UserInfoVo tempUserInfo;
        Integer nowNum;
        Random random = new Random();

        UserInfoVo userInfoVo1 = null;
        UserInfoVo userInfoVo2 = null;
        UserInfoVo userInfoVo3 = null;

        List<User> userList = attentionDao.findThreeUserInfoVo(userId);

        for (User user : userList) {
            if (null == userInfoVo1 || null == userInfoVo2 || null == userInfoVo3) {
                nowNum = random.nextInt(10);
                if (nowNum > 7) {
                    tempUserInfo = getUserInfoVo(user, null, attentionDao);
                    if (null == userInfoVo1) {
                        userInfoVo1 = tempUserInfo;
                    } else if (null == userInfoVo2) {
                        if (userInfoVo1.getId().equals(tempUserInfo.getId())) {
                            continue;
                        }
                        userInfoVo2 = tempUserInfo;
                    } else {
                        if (userInfoVo1.getId().equals(tempUserInfo.getId()) || userInfoVo2.getId().equals(tempUserInfo.getId())) {
                            continue;
                        }
                        userInfoVo3 = tempUserInfo;
                    }
                }
            }
        }

        if (null != userInfoVo1) {
            list.add(userInfoVo1);
        }
        if (null != userInfoVo2) {
            list.add(userInfoVo2);
        }
        if (null != userInfoVo3) {
            list.add(userInfoVo3);
        }

        return list;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Page<UserInfoVo> iPageByParams(final Integer userId, final Integer type, Integer pageNum, Integer pageSize) {
        Integer[] info = CommonController.getPageParams(pageNum, pageSize);
        PageRequest pageRequest = new PageRequest(info[0] - 1, info[1], Sort.Direction.DESC, "id");

        final Page<Attention> attentionPage = attentionDao.findAll(new Specification<Attention>() {
            @SuppressWarnings("ToArrayCallWithZeroLengthArrayArgument")
            @Override
            public Predicate toPredicate(Root<Attention> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate result = null;
                List<Predicate> predicateList = new ArrayList<>();

                if (type == 1) {
                    // 粉丝列表
                    predicateList.add(cb.equal(root.get("toUser").get("id").as(Integer.class), userId));
                } else {
                    // 关注列表
                    predicateList.add(cb.equal(root.get("fromUser").get("id").as(Integer.class), userId));
                }

                if (predicateList.size() > 0) {
                    result = cb.and(predicateList.toArray(new Predicate[]{}));
                }

                if (result != null) {
                    query.where(result);
                }
                return query.getGroupRestriction();
            }

        }, pageRequest);

        List<UserInfoVo> list = new ArrayList<>();

        for (Attention attention : attentionPage.getContent()) {
            list.add(getUserInfoVo(attention, type));
        }

        return new PageImpl(list, pageRequest, attentionPage.getTotalElements());
    }

    @Override
    public void iModifyAttentionInfo(Integer userId, Integer sourceId, Integer type) throws ParamErrorException, AttentionNotFindException, AttentionExistException {
        if (null == userId || null == sourceId) {
            throw new ParamErrorException();
        }

        if (null == type) {
            type = 0;
        }

        Attention attention = attentionDao.findOneByParams(userId, sourceId);

        if (type == 0) {
            // 关注
            if (null != attention) {
                throw new AttentionExistException();
            }

            User fromUser = new User();
            fromUser.setId(userId);
            User toUser = new User();
            toUser.setId(sourceId);

            attention = new Attention();
            attention.setFromUser(fromUser);
            attention.setToUser(toUser);

            attentionDao.save(attention);
        } else {
            // 取消关注
            if (null == attention) {
                throw new AttentionNotFindException();
            }

            deleteById(attention.getId());
        }
    }

    @Override
    public Boolean isAttentionAll(Integer fromUserId, Integer toUserId) {
        Attention fromAttention = attentionDao.findOneByParams(fromUserId, toUserId);
        Attention toAttention = attentionDao.findOneByParams(toUserId, fromUserId);

        return null != fromAttention && null != toAttention;
    }

    private UserInfoVo getUserInfoVo(Attention attention, Integer isFans) {
        User user;
        UserInfoVo userInfoVo = new UserInfoVo();
        Attention fromAttention;
        Attention toAttention;

        // 1=粉丝，2=关注
        if (isFans == 1) {
            user = attention.getFromUser();

            toAttention = attentionDao.findOneByParams(user.getId(), attention.getToUser().getId());
            fromAttention = attentionDao.findOneByParams(attention.getToUser().getId(), user.getId());
        } else {
            user = attention.getToUser();

            toAttention = attentionDao.findOneByParams(user.getId(), attention.getFromUser().getId());
            fromAttention = attentionDao.findOneByParams(attention.getFromUser().getId(), user.getId());
        }

        userInfoVo.setIsAttentionOther(null != fromAttention ? 1 : 0);
        userInfoVo.setIsAttentionMe(null != toAttention ? 1 : 0);

        userInfoVo.setId(user.getId());
        userInfoVo.setNickName(user.getNickName());
        userInfoVo.setAvatar(user.getAvatar());
        if (null != user.getRegion()) {
            userInfoVo.setRegionId(user.getRegion().getId());
            userInfoVo.setRegionInfo(user.getRegion().getCity().getProvince().getName() + "|" + user.getRegion().getCity().getName());
        }

        if (attention.getIsRead().equals(Constant.USER_STATUS_NO)) {
            attention.setIsRead(Constant.USER_STATUS_YES);
            attentionDao.save(attention);
        }

        return userInfoVo;
    }

    public static UserInfoVo getUserInfoVo(User user, Integer userId, AttentionDao attentionDao) {
        UserInfoVo userInfoVo = new UserInfoVo();
        userInfoVo.setId(user.getId());
        userInfoVo.setNickName(user.getNickName());
        userInfoVo.setAvatar(user.getAvatar());
        if (null != user.getRegion()) {
            userInfoVo.setRegionId(user.getRegion().getId());
            userInfoVo.setRegionInfo(user.getRegion().getCity().getProvince().getName() + "|" + user.getRegion().getCity().getName());
        }
        if (null != userId) {
            Attention fromAttention = attentionDao.findOneByParams(userId, user.getId());
            Attention toAttention = attentionDao.findOneByParams(user.getId(), userId);

            userInfoVo.setIsAttentionOther(null != fromAttention ? 1 : 0);
            userInfoVo.setIsAttentionMe(null != toAttention ? 1 : 0);
        }

        return userInfoVo;
    }
}